/*
 * Agent Client
 *
 * Created by Xiaowen.Zhu
 */

#include "cybertron/node/AgentClient.hpp"
#include <iostream>

CYBERTRON_BEGIN


    AgentClient::AgentClient(const std::string &srvAddr, int srvPort)
            : mpClient(nullptr),
              mState(AGENT_CLIENT_STATE_DISCONNECTED),
              mFuncOnDisconnected(nullptr),
              mFuncOnConnected(nullptr),
              mFuncOnMessage(nullptr),
              mServerAddr(srvAddr),
              mServerPort(srvPort) {
        perform();
    }

    AgentClient::~AgentClient() {
        std::lock_guard<std::recursive_mutex> lock(mLock);
        if (mpClient) {
            mpClient->close(nullptr);
            mpClient = nullptr;
        }
    }

    bool AgentClient::sendMessage(const Message &msg) {
        std::lock_guard<std::recursive_mutex> lock(mLock);
        if (mState == AGENT_CLIENT_STATE_CONNECTED) {
            mpClient->send(msg);
            return true;
        } else {
            return false;
        }
    }

    bool AgentClient::sendMessage(std::uint16_t msgId, const google::protobuf::MessageLite & protobufMsg)
    {
        std::lock_guard<std::recursive_mutex> lock(mLock);
        if (mState == AGENT_CLIENT_STATE_CONNECTED) {
            mpClient->send(msgId, protobufMsg);
            return true;
        } else {
            return false;
        }
    }


    void AgentClient::setHandlerDisconnected(std::function<void()> funcOnDisconnected) {
        mFuncOnDisconnected = funcOnDisconnected;
    }

    void AgentClient::setHandlerConnected(std::function<void()> funcOnConnected) {
        mFuncOnConnected = funcOnConnected;
    }

    void AgentClient::setHandlerMessage(std::function<void(const Message &)> funcOnMessage) {
        mFuncOnMessage = funcOnMessage;
    }

    void AgentClient::onTimer() {
        perform();
    }

    void AgentClient::perform() {
        std::lock_guard<std::recursive_mutex> lock(mLock);
        if (mpClient) {
            mpClient->onTimer();
        }

        if (mState == AGENT_CLIENT_STATE_CONNECTING || mState == AGENT_CLIENT_STATE_CONNECTED) {
            return;
        }

        if (mpClient) {
            mpClient->close("disconnected");
            mpClient = nullptr;
        }
        mpClient = std::make_shared<SocketTcpClient>();
        mpClient->setHandlerConnected(
                [this]() {
                    onConnected();
                }
        );
        mpClient->setHandlerDisconnected(
                [this]() {
                    onDisconnected();
                }
        );
        mpClient->setHandlerMessage(
                [this](const Message &msg) {
                    onMessage(msg);
                }
        );
        mpClient->connect(mServerAddr, mServerPort);
        mState = AGENT_CLIENT_STATE_CONNECTING;
    }

    void AgentClient::onDisconnected() {
        mState = AGENT_CLIENT_STATE_DISCONNECTED;
        if (mFuncOnDisconnected) {
            mFuncOnDisconnected();
        }
    }

    void AgentClient::onConnected() {
        mState = AGENT_CLIENT_STATE_CONNECTED;
        if (mFuncOnConnected) {
            mFuncOnConnected();
        }
    }

    void AgentClient::onMessage(const Message &msg) {
        if (mFuncOnMessage) {
            mFuncOnMessage(msg);
        }
    }

CYBERTRON_END

